﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Text;
using System.Web;
using UDS.Components;

namespace UDS.Entity
{
    public static class CommonFile
    {
        public const string AttachVDir = @"~\Files\CommonFiles\";

        public static void AddFile(CFFileInfo fileInfo, HttpPostedFile postedFile)
        {
            var parameters = new SqlParameter[]
            {
                Database.MakeOutParam("@fileId", SqlDbType.Int, 4),
                Database.MakeInParam("@catalogId", SqlDbType.Int, 4, fileInfo.CatalogID),
                Database.MakeInParam("@name", SqlDbType.NVarChar, 256, fileInfo.Name),
                Database.MakeInParam("@version", SqlDbType.NVarChar, 64, fileInfo.Version),
                Database.MakeInParam("@size", SqlDbType.Int, 4, fileInfo.Size),
                Database.MakeInParam("@vPath", SqlDbType.NVarChar, 512, null),
                Database.MakeInParam("@invalid", SqlDbType.Bit, 1, fileInfo.Invalid),
                Database.MakeInParam("@creator", SqlDbType.NVarChar, 50, fileInfo.Creator),
                Database.MakeInParam("@createNew", SqlDbType.Bit, 1, true),
            };

            using (var db = new Database())
            {
                using (db.BeginTransaction())
                {
                    // First create a new record in database
                    db.RunProc("dbo.sproc_CF_AddUpdateFile_V2", parameters);

                    string fileName = HttpUtil.GetNameOfPostedFile(postedFile);
                    if (!string.IsNullOrEmpty(fileName))
                    {
                        int fileId = (int)parameters[0].Value;
                        string vPath = string.Concat(AttachVDir, fileId.ToString(), "\\", fileName);
                        string physicalPath = HttpUtil.MapPath(vPath);

                        // Ensure the directory exists
                        DirectoryInfo dirInfo = new DirectoryInfo(Path.GetDirectoryName(physicalPath));
                        if (!dirInfo.Exists)
                        {
                            dirInfo.Create();
                        }

                        // Save the file
                        postedFile.SaveAs(physicalPath);

                        // Update the v-path of the file in database.
                        fileInfo.FileID = fileId;
                        fileInfo.VPath = vPath;
                        UpdateFileInfo(db, fileInfo);
                    }

                    // Finally commit the transaction
                    db.Commit();
                }
            }
        }

        public static void UpdateFile(CFFileInfo fileInfo, HttpPostedFile postedFile)
        {
            using (var db = new Database())
            {
                using (db.BeginTransaction())
                {
                    string fileName = HttpUtil.GetNameOfPostedFile(postedFile);
                    if (string.IsNullOrEmpty(fileName))
                    {
                        // Just simply update the basic info of the file
                        UpdateFileInfo(db, fileInfo);
                    }
                    else
                    {
                        string vPath = string.Concat(AttachVDir, fileInfo.FileID.ToString(), "\\", fileName);
                        fileInfo.VPath = vPath;
                        UpdateFileInfo(db, fileInfo);

                        // Save the file to the specified v-path
                        string physicalPath = HttpUtil.MapPath(vPath);
                        DirectoryInfo dirInfo = new DirectoryInfo(Path.GetDirectoryName(physicalPath));
                        if (!dirInfo.Exists)
                        {
                            dirInfo.Create();
                        }
                        postedFile.SaveAs(physicalPath);
                    }

                    // Finally commit the transaction
                    db.Commit();
                }
            }
        }

        public static void DeleteFiles(int[] files)
        {
            if (files != null && files.Length > 0)
            {
                /*
                 * XML format
                 * <files>
                 *  <file id="" />
                 * </files>
                 */
                string xml = Utility.GenerateXML(files, "files", "file", "id");
                var parameters = new[]
                {
                    Database.MakeInParam("@fileIdXml", SqlDbType.Xml, -1, xml),
                };

                using (var db = new Database())
                {
                    // Create a new transaction to finish the job.
                    using (db.BeginTransaction())
                    {
                        using (var dr = db.RunDataReader("dbo.sproc_CF_DeleteFiles_V2", parameters))
                        {
                            while (dr.Read())
                            {
                                // TODO:
                                // Remove the attachment files
                            }
                        }

                        // Commit the transaction
                        db.Commit();
                    }
                }
            }
        }

        /// <summary>
        /// Get all files in the given catalog (or -1 to get all files).
        /// </summary>
        public static IList<CFFileInfo> GetFilesByCatalog(int catalogId)
        {
            var parameters = new SqlParameter[]
            {
                Database.MakeInParam("@catalogId", SqlDbType.Int, 4, catalogId),
            };

            using (var db = new Database())
            {
                using (var dr = db.RunDataReader("dbo.sproc_CF_GetFilesByCatalog_V2", parameters))
                {
                    List<CFFileInfo> list = new List<CFFileInfo>();
                    while (dr.Read())
                    {
                        list.Add(CFFileInfo.ReadFileInfo(dr));
                    }

                    return list;
                }
            }
        }

        /// <summary>
        /// Get the information of the given file.
        /// </summary>
        public static CFFileInfo GetFile(int fileId)
        {
            var parameters = new SqlParameter[]
            {
                Database.MakeInParam("@fileID", SqlDbType.Int, 4, fileId),
            };

            using (var db = new Database())
            {
                using (var dr = db.RunDataReader("dbo.sproc_CF_GetFile_V2", parameters))
                {
                    if (dr.Read())
                    {
                        return CFFileInfo.ReadFileInfo(dr);
                    }
                }
            }
            return null;
        }

        /// <summary>
        /// Get all catalogs.
        /// </summary>
        public static IList<CatalogInfo> GetCatalogs()
        {
            using (var db = new Database())
            {
                using (var dr = db.RunDataReader("dbo.sproc_CF_GetAllCatalogs_V2", null))
                {
                    List<CatalogInfo> list = new List<CatalogInfo>();
                    while (dr.Read())
                    {
                        list.Add(CatalogInfo.ReadCatalogInfo(dr));
                    }

                    return list;
                }
            }
        }

        public static void AddUpdateCatalog(CatalogInfo catalog)
        {
            var parameters = new SqlParameter[]
            {
                Database.MakeInParam("@catalog", SqlDbType.NVarChar, 255, catalog.Catalog),
                Database.MakeInParam("@creator", SqlDbType.NVarChar, 50, catalog.Creator),
                Database.MakeInParam("@createNew", SqlDbType.Bit, 1, (catalog.CatalogID == -1)),
                Database.MakeInParam("@catalogId", SqlDbType.Int, 4, catalog.CatalogID),
            };

            using (var db = new Database())
            {
                db.RunProc("dbo.sproc_CF_AddUpdateCatalog_V2", parameters);
            }
        }

        public static bool DeleteCatalog(int catalogId)
        {
            var parameters = new SqlParameter[]
            {
                Database.MakeInParam("@catalogId", SqlDbType.Int, 4, catalogId),
            };

            using (var db = new Database())
            {
                int r = db.RunProc("dbo.sproc_CF_DeleteCatalog_V2", parameters);
                return r == 0;
            }
        }

        private static void UpdateFileInfo(Database db, CFFileInfo fileInfo)
        {
            var parameters = new SqlParameter[]
            {
                Database.MakeInParam("@fileId", SqlDbType.Int, 4, fileInfo.FileID),
                Database.MakeInParam("@catalogId", SqlDbType.Int, 4, fileInfo.CatalogID),
                Database.MakeInParam("@name", SqlDbType.NVarChar, 256, fileInfo.Name),
                Database.MakeInParam("@version", SqlDbType.NVarChar, 64, fileInfo.Version),
                Database.MakeInParam("@size", SqlDbType.Int, 4, fileInfo.Size),
                Database.MakeInParam("@vPath", SqlDbType.NVarChar, 512, fileInfo.VPath),
                Database.MakeInParam("@invalid", SqlDbType.Bit, 1, fileInfo.Invalid),
                Database.MakeInParam("@creator", SqlDbType.NVarChar, 50, fileInfo.Creator),
                Database.MakeInParam("@createNew", SqlDbType.Bit, 1, false),
            };

            db.RunProc("dbo.sproc_CF_AddUpdateFile_V2", parameters);
        }
    }
}
